package com.stone.starter.core.interceptor.manager;

import com.google.common.collect.ImmutableMap;
import com.stone.starter.core.interceptor.*;
import com.stone.starter.core.interceptor.interceptors.HandlerInterceptor;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 抽象拦截器链管理器
 *
 * @author Mr_wenpan@163.com 2021/11/30 10:33 上午
 */
public abstract class AbstractInterceptorChainManager<T> {

    private static final Logger LOGGER = LoggerFactory.getLogger(AbstractInterceptorChainManager.class);

    private final Map<ChainId, InterceptorChain<T>> chainMap;

    public AbstractInterceptorChainManager(List<HandlerInterceptor<T>> interceptorList,
                                           List<InterceptorChainConfigurer<T, InterceptorChainBuilder<T>>> configurerList) {

        chainMap = ImmutableMap.copyOf(initInterceptorChain(interceptorList, configurerList));
        LOGGER.info("Register {} InterceptorChain, names are [{}]", chainMap.size(),
                chainMap.keySet().stream().map(ChainId::id).collect(Collectors.joining(",")));
    }

    /**
     * 初始化拦截器链
     *
     * @param interceptorList 拦截器集合
     * @param configurerList  拦截器链配置类集合
     * @return java.util.Map<ChainId, InterceptorChain < T>> key: 一条执行链的ID，value：执行链对象
     * @author Mr_wenpan@163.com 2021/11/30 11:04 上午
     */
    private Map<ChainId, InterceptorChain<T>> initInterceptorChain(List<HandlerInterceptor<T>> interceptorList,
                                                                   List<InterceptorChainConfigurer<T, InterceptorChainBuilder<T>>> configurerList) {
        if (CollectionUtils.isEmpty(interceptorList)) {
            throw new IllegalArgumentException("Interceptors is empty.");
        }

        if (CollectionUtils.isEmpty(configurerList)) {
            throw new IllegalArgumentException("Interceptor configurers is empty.");
        }

        InterceptorChainBuilder<T> builder = new InterceptorChainBuilder<>(interceptorList);

        // 配置类按照@order注解排序
        configurerList.sort(AnnotationAwareOrderComparator.INSTANCE);

        // 遍历每一个拦截器链配置类，这一步其实是将所有配置类中的拦截器按前后顺序都放入到builder中的map集合里
        configurerList.forEach(configurer -> {
            configurer.configure(builder);
            builder.clearChain();
        });

        // 将一组组的前置、后置拦截器组成一个个的InterceptorChain
        List<InterceptorChain<T>> chains = builder.performBuild();

        return chains.stream().collect(Collectors.toMap(InterceptorChain::getChainId, Function.identity()));
    }


    /**
     * 拦截器调用入口，将核心操作封装成 Consumer 对象传入。
     *
     * @param target    The target to handle.
     * @param operation The core operation to intercept.
     */
    public final void doInterceptor(ChainId chainId, T target, Operation<T> operation) {
        InterceptorChain<T> chain = chainMap.get(chainId);
        if (chain == null) {
            // 应该抛自定义异常
            throw new RuntimeException("InterceptorChain Not Found For [" + chainId.id() + "]");
        }

        chain.doExecute(target, operation);
    }

    public final void doInterceptor(ChainId chainId, T target) {
        InterceptorChain<T> chain = chainMap.get(chainId);
        if (chain == null) {
            // 应该抛自定义异常
            throw new RuntimeException("InterceptorChain Not Found For [" + chainId.id() + "]");
        }

        chain.doExecute(target, null);
    }

}